Skip to content

文章参考刨根问底,kafka到底会不会丢消息_kafka_爱笑的架构师_InfoQ写作社区

三种消息传递语义

Kafka 中消息传递语义主要分为以下三种:

  • At most once(最多一次):消息可能会丢失,但绝不会重复传输。
  • At least once(至少一次):消息绝不会丢失,但可能会重复传输。
  • Exactly once(精确一次):消息绝不会丢失,且只会被传输一次。

消息丢失场景分析

1. Producer 端

Producer 端的消息丢失与 ACK (Acknowledge) 机制紧密相关。

三种 ACK 配置

  • 0:Producer 发送消息后不等待任何确认(Fire and Forget)。
  • 1:Leader 副本将消息写入本地日志后即返回 ACK,不等待 Follower 同步。
  • all (-1):Leader 等待所有 ISR(In-Sync Replicas)集合中的副本同步完成后才返回 ACK。

是否会丢消息?

  • ACK = 0会丢。发送出去即视为成功,若发送过程中网络故障或 Broker 宕机,消息直接丢失。
  • ACK = 1会丢。如果 Leader 接收消息并 ACK 后,在同步给 Follower 之前挂掉,此时集群选举了未同步该消息的 Follower 成为新 Leader,则该消息丢失。
  • ACK = all不丢(配合 min.insync.replicas 参数配置得当的情况下)。

2. Broker 端

  • 会丢:Kafka 为了高性能,消息是先写入操作系统的 Page Cache。如果数据写入 Cache 后,在操作系统进行刷盘(fsync)之前机器宕机断电,内存中的数据将会丢失。

3. Consumer 端

Consumer 端的消息丢失取决于 Offset Commit(提交偏移量) 的时机。

两种 Commit 场景

  • 先消费再 Commit不丢
    • 逻辑:获取消息 -> 执行业务逻辑 -> 提交 Offset。
    • 风险:如果消费成功但在 Commit 前宕机,重启后会重新拉取该消息,导致重复消费
  • 先 Commit 再消费会丢
    • 逻辑:获取消息 -> 提交 Offset -> 执行业务逻辑。
    • 风险:如果 Commit 成功但业务逻辑执行失败(或服务宕机),该消息已被标记为“已消费”,实际业务未处理,导致丢失。

总结与最佳实践

  • Broker 端:极端情况下(Page Cache 刷盘间隙)会丢消息,且物理层面上无法完全避免(除非同步刷盘,但这会极大牺牲吞吐量)。
  • P/C 端(Producer/Consumer):可以通过配置(acks=all)和代码逻辑(先消费后提交)避免丢失,但这通常会带来重复消费的问题。
  • 核心权衡:需要在 消息不丢失系统吞吐量/性能 之间做权衡。
  • 最佳实践:永远不要完全依赖中间件保证 100% 可靠性。业务侧做好补偿机制(如本地消息表、日志记录、定期对账等),做好消息丢失的兜底方案。